<script setup lang="ts">
import { computed, onMounted, onUnmounted, watch } from "vue"

const props = withDefaults(
    defineProps<{
        show?: boolean
        maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl"
        closeable?: boolean
    }>(),
    {
        show: false,
        maxWidth: "2xl",
        closeable: true,
    },
)

const emit = defineEmits<{
    (e: "close"): void
}>()

watch(
    () => props.show,
    () => {
        if (props.show) {
            document.body.style.overflow = "hidden"
        } else {
            document.body.style.overflow = "visible"
        }
    },
)

const close = () => {
    if (props.closeable) {
        emit("close")
    }
}

const closeOnEscape = (e: KeyboardEvent) => {
    if (e.key === "Escape" && props.show) {
        close()
    }
}

onMounted(() => document.addEventListener("keydown", closeOnEscape))

onUnmounted(() => {
    document.removeEventListener("keydown", closeOnEscape)
    document.body.style.overflow = "visible"
})

const maxWidthClass = computed(() => {
    return {
        sm: "sm:max-w-sm",
        md: "sm:max-w-md",
        lg: "sm:max-w-lg",
        xl: "sm:max-w-xl",
        "2xl": "sm:max-w-2xl",
    }[props.maxWidth]
})
</script>

<template>
    <Teleport to="body">
        <Transition leave-active-class="duration-200">
            <div v-show="show" class="fixed inset-0 z-50 overflow-y-auto px-4 py-6 sm:px-0" scroll-region>
                <Transition enter-active-class="ease-out duration-300" enter-from-class="opacity-0" enter-to-class="opacity-100" leave-active-class="ease-in duration-200" leave-from-class="opacity-100" leave-to-class="opacity-0">
                    <div v-show="show" class="fixed inset-0 transition-all" @click="close">
                        <div class="absolute inset-0 bg-gray-500 opacity-75" />
                    </div>
                </Transition>

                <Transition enter-active-class="ease-out duration-300" enter-from-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enter-to-class="opacity-100 translate-y-0 sm:scale-100" leave-active-class="ease-in duration-200" leave-from-class="opacity-100 translate-y-0 sm:scale-100" leave-to-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
                    <div v-show="show" class="relative z-50 mb-6 overflow-hidden rounded-lg bg-white shadow-xl transition-all sm:mx-auto sm:w-full" :class="maxWidthClass">
                        <slot v-if="show" />
                    </div>
                </Transition>
            </div>
        </Transition>
    </Teleport>
</template>
